/**
 * Implementation of peel node entity.
 *
 * \file node_impl.hpp
 * \author tomby
 * \date 04-01-2009
 **/

/*  Copyright (C) 2009  Tomas 'tomby' Bily

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */


#ifndef __DBC_NODE_IMPL__
#define __DBC_NODE_IMPL__

namespace dbc {
  namespace peel {

    class Edge;

    inline void Node::add_edge (Edge* edge, dbc::PCEntity::EcontainerPtr& cont, Node::edge_iter* iters)
    {
      if (cont->empty ())
	{
	  cont->push_back (edge);
	  switch (edge->get_etype ())
	    {
	    case Edge::EMERGE:
	      iters[0] = iters[1] = edge_iter (cont->end ());
	      break;
	    case Edge::SINK:
	      iters [0] = edge_iter (cont->begin ()); iters [1] = edge_iter (cont->end ());
	      break;
	    case Edge::INTERACT:
	      iters [0] = iters [1] = edge_iter (cont->begin ());
	      break;
	    }
	}
      else 
	{
	  switch (edge->get_etype ())
	    {
	    case Edge::EMERGE:
	      cont->insert (iters [0].get (), edge);
	      break;
	    case Edge::SINK:
	      if (iters [0] == iters [1])
		iters [0] = cont->insert (iters [1].get (), edge);
	      else
		cont->insert (iters [1].get (), edge);
	      break;
	    case Edge::INTERACT:
	      if (iters [1].get () == cont->end ())
		{
		  if (iters [0] == iters [1])
		    iters [0] = iters [1] = edge_iter (cont->insert (iters [1].get (), edge));
		  else
		    iters [1] = edge_iter (cont->insert (iters [1].get (), edge));
		}
	      else 
		cont->push_back (edge);
	      break;
	    }
	}
    }

    inline void Node::add_in_edge (Edge* edge)
    { add_edge (edge, get_producers (), esi_trig_i); }

    inline void Node::add_out_edge (Edge* edge)
    { add_edge (edge, get_consumers (), esi_trig_o); }

    inline Node::edge_iter Node::begin_in_edge (Edge::EdgeType type)
    {
      if (get_producers ()->empty ())
	return get_producers ()->end ();

      switch (type)
	{
	case Edge::EMERGE:
	  return get_producers ()->begin ();
	case Edge::SINK:
	  return esi_trig_i [0];
	case Edge::INTERACT:
	  break;
	}
      return esi_trig_i [1];
    }
    
    inline Node::edge_iter Node::end_in_edge (Edge::EdgeType type)
    {
      if (get_producers ()->empty ())
	return get_producers ()->end ();

      switch (type)
	{
      	case Edge::EMERGE:
	  return esi_trig_i [0];
	case Edge::SINK:
	  return esi_trig_i [1];
	case Edge::INTERACT:
	  break;
	}
      return get_producers ()->end ();
    }

    inline Node::edge_iter Node::begin_out_edge (Edge::EdgeType type)
    {
      if (get_consumers ()->empty ())
	return get_consumers ()->end ();

      switch (type)
	{
	case Edge::EMERGE:
	  return get_consumers ()->begin ();
	case Edge::SINK:
	  return esi_trig_o [0];
	case Edge::INTERACT:
	  break;
	}
      return esi_trig_o [1];
    }

    inline Node::edge_iter Node::end_out_edge (Edge::EdgeType type)
    {
      if (get_consumers ()->empty ())
	return get_consumers ()->end ();

      switch (type)
	{
	case Edge::EMERGE:
	  return esi_trig_o [0];
	case Edge::SINK:
	  return esi_trig_o [1];
	case Edge::INTERACT:
	  break;
	}
      return get_consumers ()->end ();
    }
  };
};

#endif
